package com.lingo.a2b.common.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lingo.a2b.common.handler.ValueConvertHandler;
import com.lingo.a2b.common.util.model.ClassFieldNode;
import com.lingo.a2b.common.util.model.ClassFieldTree;
import com.lingo.a2b.common.util.model.NestedFieldPackBo;
import com.lingo.a2b.model.entity.ConnectFieldRelative;
import com.lingo.a2b.model.entity.ConnectProjectDO;
import com.lingo.a2b.service.ConnectFieldRelativeService;
import com.lingo.a2b.service.ConnectProjectService;
import com.lingo.a2b.service.ValueConvertService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author lingo
 * @date 2020/5/23 12:41
 * @Company: www.xyb2b.com
 */
@Component
public class TranslateUtils {

    @Autowired
    private ValueConvertService valueConvertService;
    @Autowired
    private ConnectFieldRelativeService connectFieldRelativeService;
    @Autowired
    private ConnectProjectService connectProjectService;

    public JSONObject extractTree(ClassFieldTree tree,Object data){
        tree.setData(data);
        List<ClassFieldNode> fieldNodeList = tree.getFieldNodeList();
        JSONObject topJson = new JSONObject(true);
        if (CollectionUtils.isEmpty(fieldNodeList)){
            return topJson;
        }
        for (ClassFieldNode nodeInfo : fieldNodeList) {
            // 在topJson中，初始化 当前node 的父节点
            JSONObject fatherJson = getFatherJson(topJson, nodeInfo.getTargetName());
            JSONObject jsonObject = addSunNode(nodeInfo, tree.getData(), tree.getData());
            fatherJson.putAll(jsonObject);
        }
        return topJson;
    }

    private JSONObject addSunNode(ClassFieldNode nodeInfo,Object nowData,Object globalData){
        JSONObject temp = new JSONObject();
        String realName = getRealName(nodeInfo.getTargetName());
        Object value = getValue(nodeInfo,nowData,globalData);
        temp.put(realName,value);
        return temp;
    }

    private JSONObject getFatherJson(JSONObject topJson,String targetName) {
        if (!PackUtils.isNestedFieldName(targetName)) {
            return topJson;
        }
        String[] split = PackUtils.split(targetName);
        JSONObject nowJson = topJson;
        for (String s : split) {
            Object newJson = nowJson.get(s);
            if (newJson == null){
                newJson = new JSONObject();
                nowJson.put(s,newJson);
            }
            nowJson = (JSONObject) newJson;
        }
        return nowJson;
    }

    private Object getValue(ClassFieldNode nodeInfo, Object nowData,Object globalData) {
        Boolean fisCollection = nodeInfo.getFisCollection();
        Object fieldValue = ReflectionUtils.getValue(nodeInfo.getField(), nowData);
        ValueConvertHandler handler = nodeInfo.getHandler();
        if (!fisCollection){
            Object value = handler.translate(fieldValue, globalData);
            return value;
        }
        Collection list = (Collection) fieldValue;
        JSONArray valueList = new JSONArray();
        // 没有 子域的直接翻译
        if (CollectionUtils.isEmpty(nodeInfo.getSunNodeList())){
            list.forEach(v ->{
                Object value = handler.translate(v, globalData);
                valueList.add(value);
            });
        }else{
            list.forEach(v ->{
                List<ClassFieldNode> sunNodeList = nodeInfo.getSunNodeList();
                JSONObject oneContent = new JSONObject();
                for (ClassFieldNode sunNode : sunNodeList) {
                    JSONObject temp = addSunNode(sunNode, v, globalData);
                    oneContent.putAll(temp);
                }
                valueList.add(oneContent);
            });
        }
        return valueList;
    }

    private String getRealName(String targetName) {
        if (!PackUtils.isNestedFieldName(targetName)){
            return targetName;
        }
        return PackUtils.unpackNestedFieldName(targetName).getNowFieldName();
    }

    public ClassFieldTree projectToTree(int projectId) {
        ConnectProjectDO one = connectProjectService.getById(projectId);
        Assert.notNull(one,"Illegal ProjectId: " + projectId);
        return this.projectToTree(one);
    }

    @SneakyThrows
    public ClassFieldTree projectToTree(ConnectProjectDO one){
        List<ConnectFieldRelative> fieldList = connectFieldRelativeService.listByProjectId(one.getFid());
        Set<String> fieldClasses = fieldList.stream().map(ConnectFieldRelative::getFlocateClassName).collect(Collectors.toSet());
        Map<String, Map<String, Field>> classNameToFieldMap = fieldClasses.stream().collect(Collectors.toMap(Function.identity(), this::classNameToFieldMap));
        ClassFieldTree tree = new ClassFieldTree();
        tree.setProjectId(one.getFid());
        tree.setProjectName(one.getFprojectText());
        tree.setVoClass(Class.forName(one.getFvoClassName()));
        ArrayList<ClassFieldNode> fieldNodeList = new ArrayList<>();
        tree.setFieldNodeList(fieldNodeList);
        Map<String,ClassFieldNode> fatherFieldNameToNode = new HashMap<>(fieldList.size());
        tree.setFieldNodeList(fieldNodeList);
        for (ConnectFieldRelative relativeInfo : fieldList) {
            String fsrcFieldName = relativeInfo.getFsrcFieldName();
            String ftargetFieldName = relativeInfo.getFtargetFieldName();
            String realName = relativeInfo.getFsrcFieldName();
            ClassFieldNode newNode = new ClassFieldNode();
            fatherFieldNameToNode.put(fsrcFieldName,newNode);
            boolean nestedFieldName = PackUtils.isNestedFieldName(fsrcFieldName);
            if (nestedFieldName){
                // 去掉前面重复的嵌套，避免后面重复建字段
                NestedFieldPackBo bo = PackUtils.unpackNestedFieldName(fsrcFieldName);
                ClassFieldNode fatherNode = getFatherNode(fatherFieldNameToNode, bo.getPreFieldName());
                if (CollectionUtils.isEmpty(fatherNode.getSunNodeList())){
                    fatherNode.setSunNodeList(new ArrayList<>());
                }
                fatherNode.getSunNodeList().add(newNode);
                realName = bo.getNowFieldName();
            }
            else{
                fieldNodeList.add(newNode);
            }
            Field field = classNameToFieldMap.get(relativeInfo.getFlocateClassName()).get(realName);
            if (relativeInfo.getFisCollection()){
                //如果是一个集合
                newNode.setFisCollection(true);
                newNode.setFieldClass(ReflectionUtils.getRealType(field));
            }else{
                newNode.setFisCollection(false);
                newNode.setFieldClass(Class.forName(relativeInfo.getFlocateClassName()));
            }
            newNode.setField(field);
            newNode.setFieldName(realName);
            newNode.setTargetName(ftargetFieldName);
            newNode.setHandler(valueConvertService.getHandlerByCode(relativeInfo.getFvalueConvertId()));
        }
        return tree;
    }

    private ClassFieldNode getFatherNode(Map<String,ClassFieldNode> fieldNodeMap, String key){
        ClassFieldNode classFieldNode = fieldNodeMap.get(key);
        return classFieldNode;
    }


    @SneakyThrows
    private Map<String, Field> classNameToFieldMap(String className){
        Class<?> aClass = Class.forName(className);
        Map<String, Field> classFieldMap = ReflectionUtils.getClassFieldMap(aClass);
        return classFieldMap;
    }

}
